先前設計的大多是給管理者的介面,今天則是來設計前端介面,讓外部使用者來做存取。
圖書館會員使用前端功能時,可以為會員分配一個使用者登入名,以存取其圖書結帳請求。
我們會在新增一個模組,library_portal,/manifest.py,
{
"name": "Library Portal",
"description": "Portal for library members",
"author": "Daniel Reis",
"license": "AGPL-3",
"depends": [
"library_checkout", "portal"
],
"data": [
"security/library_security.xml",
"security/ir.model.access.csv",
"views/main_templates.xml",
"views/checkout_portal_templates.xml",
],
}
設置一個前端介面,需要兩個元件 web controller(存取特定URL時觸發)跟QWeb template(產生由該URL呈現的HTML)
到__init__.py
from . import controllers
controllers/init.py
from . import main
controllers/main.py
from odoo import http
class Main(http.Controller):
@http.route("/library/catalog", auth="public", website=True)
def catalog(self, **kwargs):
Book = http.request.env["library.book"]
books = Book.sudo().search([])
res = http.request.render(
"library_portal.book_catalog",
{"books": books},
)
library_portal/views/main_templates.xml
<odoo>
<template id="book_catalog" name="Book List">
<t t-call="web.frontend_layout">
<t t-set="title">Book Catalog</t>
<div class="oe_structure">
<div class="container">
<h1 class="h1-book-catalog">
Book Catalog</h1>
<table class="table">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Published</th>
<th scope="col">Publisher</th>
</tr>
</thead>
<tbody>
<t t-foreach="books" t-as="book">
<tr scope="row">
<td><span t-field="book.name" /></td>
<td><span t-field="book.date_published"/></td>
<td><span t-field="book.publisher_id"/></td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</t>
</template>
</odoo>
另外之前也有學過怎麼新增css或js。
library_portal/static/src/css/library.css
.h1-book-catalog {
font-size: 62px;
}
在library_portal/manifest.py
"assets": {
"web.assets_backend": {
"library_portal/static/src/css/library.css",
}
},
基本介面有了,之後來新增入口網站功能,分成三個access security,controllers,QWeb templates
設置用戶的安全性,security/ir.model.access.csv:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_book_portal,Book Portal Access,library_app.model_library_book,base.group_portal,1,0,0,0
access_member_portal,Member Portal Access,library_member.model_library_member,base.group_portal,1,0,0,0
access_stage_portal,Checkout Stage Portal Access,library_checkout.model_library_checkout_stage,base.group_portal,1,0,0,0
access_checkout_portal,Checkout Portal Access,library_checkout.model_library_checkout,base.group_portal,1,0,0,0
access_checkout_portal_line,Checkout Portal Line Access,library_checkout.model_library_checkout_line,base.group_portal,1,0,0,0
security/library_security.xml
<odoo>
<data noupdate="1">
<record id="member_portal_rule" model="ir.rule">
<field name="name">
Library Member Portal Access</field>
<field name="model_id"
ref= "library_member.model_library_member"/>
<field name="domain_force"
>[('partner_id', '=',
user.partner_id.id)]</field>
<field name="groups"
eval="[(4,ref('base.group_portal'))]"/>
</record>
<record id="checkout_portal_rule" model="ir.rule">
<field name="name">
Library Checkout Portal Access</field>
<field name="model_id"
ref="library_checkout.model_library_checkout"/>
<field name="domain_force"
>[('member_id.partner_id', '=',
user.partner_id.id)]</field>
<field name="groups"
eval="[(4,ref('base.group_portal'))]"/>
</record>
</data>
</odoo>
自己的帳戶會顯示多種可用的文件類型,例如銷售訂單和發票,以及每種類型的項目數量。在controllers/init.py新增:
from . import portal
controllers/portal.py
from odoo.http import route, request
from odoo.addons.portal.controllers import portal
class CustomerPortal(portal.CustomerPortal):
def _prepare_home_portal_values(self, counters):
values = super()
._prepare_home_portal_values(counters)
if "book_checkout_count" in counters:
count =
request.env[
"library.checkout"].search_count([])
values["book_checkout_count"] = count
return values
views/portal_templates.py
<odoo>
<template id="portal_my_home"
inherit_id="portal.portal_my_home"
name="Show Book Checkouts" priority="100"
customize_show="True">
<xpath expr="//div[hasclass('o_portal_docs')]"
position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Book Checkouts</t>
<t t-set="url"
t-value="'/my/book-checkouts'"/>
<t t-set="placeholder_count"
t-value="'book_checkout_count'"/>
</t>
</xpath>
</template>
在自己的帳戶主頁列出了各種可用的文件類型。
controllers/portal.py
@route(
["/my/book-checkouts", "/my/book-checkouts/page/<int:page>"],
auth="user",
website=True,
)
def my_book_checkouts(self, page=1, **kw):
Checkout = request.env["library.checkout"]
domain = []
# Prepare pager data
checkout_count = Checkout.search_count(domain)
pager_data = portal.pager(
url="/my/book_checkouts",
total=checkout_count,
page=page,
step=self._items_per_page,
)
# Recordset according to pager and domain filter
checkouts = Checkout.search(
domain, limit=self._items_per_page, offset=pager_data["offset"]
)
# Prepare template values
values = self._prepare_portal_layout_values()
values.update(
{
"checkouts": checkouts,
"page_name": "book-checkouts",
"default_url": "/my/book-checkouts",
"pager": pager_data,
}
)
return request.render("library_portal.my_book_checkouts", values)
views/portal_templates.xml
<template id="my_book_checkouts" name="My Book Checkouts">
<t t-call="portal.portal_layout">
<t t-if="checkouts" t-call="portal.portal_table">
<thead>
<tr>
<th>Title</th>
<th>Request Date</th>
<th>Stage</th>
</tr>
</thead>
<tbody>
<tr t-foreach="checkouts" t-as="doc">
<td>
<a t-attf-href="/my/book-checkout/{{slug(doc)}}">
<span t-field="doc.name"/>
</a>
</td>
<td>
<span t-field="doc.request_date"/>
</td>
<td>
<span t-field="doc.stage_id.name" class="badge badge-pill badge-info"/>
</td>
</tr>
</tbody>
</t>
<t t-else="">
<div class="alert alert-warning" role="alert">
There are no book checkouts.
</div>
</t>
</t>
</template>